package com.uplooking.service.impl;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import javax.transaction.Transactional;
import javax.transaction.Transactional.TxType;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.uplooking.constant.CustConstants;
import com.uplooking.constant.MQConsts;
import com.uplooking.constant.RedisConstants;
import com.uplooking.constant.ShopConstants;
import com.uplooking.dao.GoodDO;
import com.uplooking.pojo.AddrVO;
import com.uplooking.pojo.GoodVO;
import com.uplooking.pojo.OrderVO;
import com.uplooking.service.CustService;
import com.uplooking.util.PagerUtils;

@Service("custService")
public class CustServiceImpl implements CustService {

	@Autowired
	private StringRedisTemplate redis;
	
	@Autowired
	private GoodDO goodDO;

	@Override
	@Transactional(value=TxType.SUPPORTS)
	public PagerUtils getGoodList(String name, String type, int index, int size, int step) {
		long count = goodDO.count(name, type);
		PagerUtils pagerUtils = new PagerUtils(index, size, count, step);
		List<String> nos = goodDO.find(name, type, (pagerUtils.getIndex()-1)*size, size); 
		List<GoodVO> items = new ArrayList<GoodVO>();
		for(String no:nos) {
			String text = redis.opsForValue().get(RedisConstants.PrefixGood+no);
			items.add(JSONObject.parseObject(text, GoodVO.class));
		}
		pagerUtils.setItems(items);
		return pagerUtils;
	}

	@Override
	public long countShopCar(String username) {
		String key = RedisConstants.PrefixShopCar+username;
		if(redis.hasKey(key)) {
			return redis.opsForList().size(key);
		}
		return 0;
	}

	@Override
	public Map<String, Object> addShopCar(String username, String gno) {
		String key = RedisConstants.PrefixShopCar+username;
		if(redis.hasKey(key)) {
			for(String no:redis.opsForList().range(key, 0, -1)) {
				if(gno.equals(no)) {
					return CustConstants.GoodExistsShopCar();
				}
			}
		}
		redis.opsForList().rightPush(key, gno);
		return CustConstants.AddShopCarSuccess();
	}

	@Override
	public Map<String, Object> delShopCar(String username, String gno) {
		String key = RedisConstants.PrefixShopCar+username;
		if(redis.hasKey(key)) {
			for(String no:redis.opsForList().range(key, 0, -1)) {
				if(gno.equals(no)) {
					redis.opsForList().remove(key, 1, gno);
					return CustConstants.DelShopCarSuccess();
				}
			}
		}
		return CustConstants.GoodNotExistsShopCar();
	}

	@Override
	public List<GoodVO> listShopCar(String username) {
		List<GoodVO> items = new ArrayList<>();
		String key = RedisConstants.PrefixShopCar+username;
		if(redis.hasKey(key)) {
			for(String no:redis.opsForList().range(key, 0, -1)) {
				String text = redis.opsForValue().get(RedisConstants.PrefixGood+no);
				items.add(JSONObject.parseObject(text, GoodVO.class));
			}
		}
		return items;
	}

	@Override
	public Map<String, Object> addAddr(String username, AddrVO addrVO) {
		String key = RedisConstants.PrefixAddress+username;
		addrVO.setAddrid(UUID.randomUUID().toString());
		addrVO.setAddrdef(false);
		redis.opsForList().rightPush(key,JSONObject.toJSONString(addrVO));
		return CustConstants.AddAddrSuccess();
	}

	@Override
	public Map<String, Object> delAddr(String username, String id) {
		String key = RedisConstants.PrefixAddress+username;
		if(redis.hasKey(key)) {
			for(String text:redis.opsForList().range(key, 0, -1)) {
				AddrVO addrVO = JSONObject.parseObject(text, AddrVO.class);
				if(id.equals(addrVO.getAddrid())) {
					redis.opsForList().remove(key, 1, text);
					return CustConstants.DelAddrSuccess();
				}
			}
		}
		return CustConstants.AddrNotExists();
	}

	@Override
	public Map<String, Object> defAddr(String username, String id) {
		String key = RedisConstants.PrefixAddress+username;
		if(redis.hasKey(key)) {
			for(String text:redis.opsForList().range(key, 0, -1)) {
				AddrVO addrVO = JSONObject.parseObject(text, AddrVO.class);
				if(id.equals(addrVO.getAddrid())) {
					redis.opsForList().remove(key, 1, text);
					addrVO.setAddrdef(true);
					redis.opsForList().leftPush(key, JSONObject.toJSONString(addrVO));
				}else {
					if(addrVO.isAddrdef()) {
						redis.opsForList().remove(key, 1, text);
						addrVO.setAddrdef(false);
						redis.opsForList().rightPush(key, JSONObject.toJSONString(addrVO));
					}
				}
			}
		}
		return CustConstants.DefAddrSuccess();
	}

	@Override
	public List<AddrVO> listAddr(String username) {
		List<AddrVO> items = new ArrayList<>();
		String key = RedisConstants.PrefixAddress+username;
		if(redis.hasKey(key)) {
			for(String text:redis.opsForList().range(key, 0, -1)) {
				items.add(JSONObject.parseObject(text, AddrVO.class));
			}
		}
		return items;
	}

	@Override
	public Map<String, Object> buyOrder(String username, String gno, String addrid, int count,String desc) {
		//先改缓存 （分布式锁） 持久化
		String lock = RedisConstants.PrefixLock+gno;
		String value = UUID.randomUUID().toString();
		//加锁 设置过期时间
		try {
			if(redis.opsForValue().setIfAbsent(lock, value, 
					RedisConstants.LockExpire, TimeUnit.SECONDS)) {
				String key = RedisConstants.PrefixGood+gno;
				if(redis.hasKey(key)) {
					String text = redis.opsForValue().get(key);
					GoodVO goodVO = JSONObject.parseObject(text, GoodVO.class);
					if(ShopConstants.GoodDownStatus == goodVO.getGstatus()) {
						return CustConstants.GoodIsDown();
					}else if(goodVO.getGleft()<count) {
						return CustConstants.GoodNotEnough();
					}else {
						//获取地址信息
						AddrVO addrVO = null;
						key = RedisConstants.PrefixAddress+username;
						for(String str:redis.opsForList().range(key, 0, -1)) {
							addrVO = JSONObject.parseObject(str, AddrVO.class);
							if(addrid.equals(addrVO.getAddrid())) {
								break;
							}
						}
						String custname = username;
						String senduser = addrVO.getSenduser();
						String sendphone = addrVO.getSendphone();
						String receiveuser = addrVO.getReceiveuser();
						String receivephone = addrVO.getReceivephone();
						String receiveaddr = addrVO.getReceiveaddr();
						String gname = goodVO.getGname();
						String gtype = goodVO.getGtype();
						String gdesc = goodVO.getGdesc();
						Double gsale = goodVO.getGsale();
						Integer gcount = count;
						String user = goodVO.getShopVO().getUser();
						String stitle = goodVO.getShopVO().getStitle();
						String svalue = goodVO.getShopVO().getSvalue();
						String sname = goodVO.getShopVO().getSname();
						String sfax = goodVO.getShopVO().getSfax();
						String saddr = goodVO.getShopVO().getSaddr();
						Timestamp otime = new Timestamp(System.currentTimeMillis());
						Integer ostatus = CustConstants.BuyOrderStatus;
						String odesc = desc;
						OrderVO orderVO = new OrderVO(custname, senduser, sendphone, receiveuser, receivephone, receiveaddr, 
								gno, gname, gtype, gdesc, gsale, gcount, 
								user, stitle, svalue, sname, sfax, saddr, 
								otime, ostatus, odesc);
						orderVO.setOmoney(gsale*gcount);
						//商品缓存数量减少
						goodVO.setGleft(goodVO.getGleft()-count);
						redis.opsForValue().set(RedisConstants.PrefixGood+gno, 
								JSONObject.toJSONString(goodVO));
						//订单生产
						redis.opsForList().rightPush(RedisConstants.PrefixOrder+username, 
								JSONObject.toJSONString(orderVO));
						return CustConstants.BuyOrderSuccess();
					}
				}else {
					return CustConstants.GoodNotExist();
				}
			}else {
				return CustConstants.LockGoodError();
			}
		} finally {
			//释放锁
			if(value.equals(redis.opsForValue().get(lock))) {
				redis.delete(lock);
			}
		}
	}
	
	@Override
	public List<OrderVO> listOrder(String username) {
		List<OrderVO> items = new ArrayList<>();
		String key = RedisConstants.PrefixOrder+username;
		if(redis.hasKey(key)) {
			for(String text:redis.opsForList().range(key, 0, -1)) {
				items.add(JSONObject.parseObject(text, OrderVO.class));
			}
		}
		return items;
	}

	@Autowired
	private RabbitTemplate rabbitTemplate;
	
	@Override
	public Map<String, Object> payForOrder(String username,String ono) {
		//消息规则
		String routingKey = MQConsts.ITEMQUEUEPRE+ono;
		//订单消息
		String key = RedisConstants.PrefixOrder+username;
		for(String text:redis.opsForList().range(key, 0, -1)) {
			OrderVO orderVO = JSONObject.parseObject(text, OrderVO.class);
			if(ono.equals(orderVO.getOno())) {
				//未支付订单转为已支付
				orderVO.setOstatus(CustConstants.PayOrderStatus);
				redis.opsForList().remove(key, 1, text);
				String object = JSONObject.toJSONString(orderVO);
				redis.opsForList().rightPush(key, object);
				//订单转交给消息队列
				rabbitTemplate.convertAndSend(MQConsts.ITEMTOPICEXCHANGE, routingKey, object);
				return CustConstants.PayForOrderSuccess();
			}
		}
		return CustConstants.LockGoodError();
	}

	@Override
	public Map<String, Object> cancelOrder(String username,String ono) {
		String key = RedisConstants.PrefixOrder+username;
		for(String text:redis.opsForList().range(key, 0, -1)) {
			OrderVO orderVO = JSONObject.parseObject(text, OrderVO.class);
			if(ono.equals(orderVO.getOno())) {
				//分布式锁
				String lock = RedisConstants.PrefixLock+orderVO.getGno();
				String value = UUID.randomUUID().toString();
				
				//订单移除
				redis.opsForList().remove(key, 1, text);
				
				//库存数量恢复
				key = RedisConstants.PrefixGood + orderVO.getGno();
				GoodVO goodVO = JSONObject.parseObject(redis.opsForValue().get(key), GoodVO.class);
				goodVO.setGleft(goodVO.getGleft()+orderVO.getGcount());
				redis.opsForValue().set(key, 
						JSONObject.toJSONString(goodVO));
				
				//释放锁
				if(value.equals(redis.opsForValue().get(lock))) {
					redis.delete(lock);
				}
				return CustConstants.CancelOrderSuccess();
			}
		}
		return CustConstants.LockGoodError();
	}
}
